#include "ota_version.h"
#include "log/log.h"
#include <unistd.h>
#include "ota_http.h"
#include "cjson/cJSON.h"
#include "openssl/sha.h"
#include "string.h"
#include "stdlib.h"
#include <sys/reboot.h>

//版本号分为三个级别 主版本、次版本、补丁版本
#define MAIN_VERSION 3
#define SUB_VERSION 0
#define PATCH_VERSION 0

/**
 * 获取文件的SHA1哈希值（40位16进制字符串）
 * 相同文件返回相同的哈希值，可用于判断文件是否相同
 * linux命令生成：sha1sum 文件名
 * 此函数可以利用AI工具帮我们生成
 */
static char *get_file_sha(char *filepath) {
    FILE *file = fopen(filepath, "rb");
    if (!file) {
        perror("Failed to open file");
        return NULL;
}

    unsigned char hash[SHA_DIGEST_LENGTH];
    SHA_CTX sha1;
SHA1_Init(&sha1);

    const int bufSize = 32768;
    unsigned char *buffer = (unsigned char *)malloc(bufSize);
    if (!buffer) {
        perror("Failed to allocate memory");
        fclose(file);
        return NULL;
}

    int bytesRead;
    while ((bytesRead = fread(buffer, 1, bufSize, file)) > 0) {
        SHA1_Update(&sha1, buffer, bytesRead);
}

    SHA1_Final(hash, &sha1);
    fclose(file);
free(buffer);

    char *outputBuffer = (char *)malloc(SHA_DIGEST_LENGTH * 2 + 1);
    if (!outputBuffer) {
        perror("Failed to allocate memory");
        return NULL;
}

    for (int i = 0; i < SHA_DIGEST_LENGTH; i++) {
        sprintf(outputBuffer + (i * 2), "%02x", hash[i]);
}

    return outputBuffer;
}



int ota_version_checkupdate(void)
{
    // 请求获取远程版本信息
    char *json = ota_http_getJson(OTA_URL_FILEINFO);
    if (json == NULL)
    {
        log_error("请求远程版本信息失败");
        free(json);
        return -1;
    }
    // 解析json，获取各级版本号
    cJSON *root = cJSON_Parse(json);
    int main = cJSON_GetObjectItem(root, "major")->valueint;
    int sub = cJSON_GetObjectItem(root, "minor")->valueint;
    int patch = cJSON_GetObjectItem(root, "patch")->valueint;
    log_debug("--远程版本号: %d.%d.%d--", main, sub, patch);
    ota_version_printVersion();
    //比较本地版本和远程版本，如果本地不小于远程版本，则不需要更新
    if (MAIN_VERSION > main 
        || (MAIN_VERSION == main && SUB_VERSION > sub) 
        || (MAIN_VERSION == main && SUB_VERSION == sub && PATCH_VERSION >= patch))
    {
        log_debug("--当前版本号不小于远程版本号，不需要更新--");
        free(json);
        cJSON_Delete(root);
        return 0;
    }
    // 需要更新，下载文件
    //删除本地文件
    unlink(OTA_LOCAL_FILE_PATH);
    int ret = ota_http_download(OTA_URL_DOWNLOAD, OTA_LOCAL_FILE_PATH);
    if (ret != 0)
    {
        free(json);
        cJSON_Delete(root);
        log_error("下载文件失败");
        return -1;
    }
    //下载成功，校验文件的合法性
    char *remote_hash = cJSON_GetObjectItem(root, "sha1")->valuestring;
    char *local_hash = get_file_sha(OTA_LOCAL_FILE_PATH); //todo
    if (strcmp(remote_hash, local_hash) != 0)
    {
        log_error("文件校验失败");
        free(local_hash);
        free(json);
        cJSON_Delete(root);
        unlink(OTA_LOCAL_FILE_PATH);
        return -1;
    }
    
    // 校验成功，重启系统， 启动新的文件
    log_debug("--文件校验成功，准备重启系统，启动新的文件--");
    reboot(RB_AUTOBOOT);  //必须是root管理员用户 ，其他用户不可以
    
    return 0;
}

int ota_version_checkupdateDaily(void)
{
    while (1)
    {
        //每日检查一次
        ota_version_checkupdate();
        //休眠24小时
        sleep(60 * 60 *24);
    }
    
    return 0;
}

void ota_version_printVersion(void)
{
    log_debug("--当前版本号: %d.%d.%d--", MAIN_VERSION, SUB_VERSION, PATCH_VERSION);
}
